﻿using NUnit.Framework;

namespace MarkupSanitizer.Tests
{
    [TestFixture]
    public class SanitizerTests
    {
        [Test]
        public void ShouldTokenizeMarkup()
        {
            const string input = "<p>Some basic <strong>markup</strong> with a few broken tags< and random ^ characters /></p><p></p>tail";
            var actual = Sanitizer.TokenizeMarkup(input);

            Assert.AreEqual(10, actual.Length);

            Assert.IsInstanceOf<MarkupTag>(actual[0]);
            Assert.AreEqual("p", ((MarkupTag)actual[0]).TagName);
            Assert.IsTrue(((MarkupTag)actual[0]).IsOpeningTag);

            Assert.IsInstanceOf<MarkupBlob>(actual[1]);
            Assert.AreEqual("Some basic ", ((MarkupBlob)actual[1]).UnescapedText);

            Assert.IsInstanceOf<MarkupTag>(actual[2]);
            Assert.AreEqual("strong", ((MarkupTag)actual[2]).TagName);
            Assert.IsTrue(((MarkupTag)actual[2]).IsOpeningTag);

            Assert.IsInstanceOf<MarkupBlob>(actual[3]);
            Assert.AreEqual("markup", ((MarkupBlob)actual[3]).UnescapedText);

            Assert.IsInstanceOf<MarkupTag>(actual[4]);
            Assert.AreEqual("strong", ((MarkupTag)actual[4]).TagName);
            Assert.IsFalse(((MarkupTag)actual[4]).IsOpeningTag);

            Assert.IsInstanceOf<MarkupBlob>(actual[5]);
            Assert.AreEqual(" with a few broken tags< and random ^ characters />", ((MarkupBlob)actual[5]).UnescapedText);

            Assert.IsInstanceOf<MarkupTag>(actual[6]);
            Assert.AreEqual("p", ((MarkupTag)actual[6]).TagName);
            Assert.IsFalse(((MarkupTag)actual[6]).IsOpeningTag);

            Assert.IsInstanceOf<MarkupTag>(actual[7]);
            Assert.AreEqual("p", ((MarkupTag)actual[7]).TagName);
            Assert.IsTrue(((MarkupTag)actual[7]).IsOpeningTag);

            Assert.IsInstanceOf<MarkupTag>(actual[8]);
            Assert.AreEqual("p", ((MarkupTag)actual[8]).TagName);
            Assert.IsFalse(((MarkupTag)actual[8]).IsOpeningTag);

            Assert.IsInstanceOf<MarkupBlob>(actual[9]);
            Assert.AreEqual("tail", ((MarkupBlob)actual[9]).UnescapedText);
        }

        [Test]
        public void ShouldTokenizePlainText()
        {
            const string input = "some plain text";
            var actual = Sanitizer.TokenizeMarkup(input);

            Assert.AreEqual(1, actual.Length);

            Assert.IsInstanceOf<MarkupBlob>(actual[0]);
            Assert.AreEqual("some plain text", ((MarkupBlob)actual[0]).UnescapedText);
        }

        [Test]
        public void ShouldTokenizeHeadText()
        {
            const string input = "head<p>markup</p>";
            var actual = Sanitizer.TokenizeMarkup(input);

            Assert.AreEqual(4, actual.Length);

            Assert.IsInstanceOf<MarkupBlob>(actual[0]);
            Assert.AreEqual("head", ((MarkupBlob)actual[0]).UnescapedText);
        }

        [Test]
        public void ShouldTokenizeTailText()
        {
            const string input = "<p>markup</p>tail";
            var actual = Sanitizer.TokenizeMarkup(input);

            Assert.AreEqual(4, actual.Length);

            Assert.IsInstanceOf<MarkupBlob>(actual[3]);
            Assert.AreEqual("tail", ((MarkupBlob)actual[3]).UnescapedText);
        }

        [Test]
        public void ShouldAllowValidMarkup()
        {
            const string input = "<p>Some basic <strong>markup</strong>.</p>";
            const string expected = "<p>Some basic <strong>markup</strong>.</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldAllowTables()
        {
            const string input = "<table><tr><td>Cell</td><td>Cell</td></tr><tr><td>Cell</td><td>Cell</td></tr></table>";
            const string expected = "<table><tr><td>Cell</td><td>Cell</td></tr><tr><td>Cell</td><td>Cell</td></tr></table>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldWrapFreeTextInAParagraph()
        {
            const string input = "some free text";
            const string expected = "<p>some free text</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldWrapFreeTextBetweenOtherElementsInAParagraph()
        {
            const string input = "<p>some structured text</p>some free text<p>some more structured text</p>";
            const string expected = "<p>some structured text</p><p>some free text</p><p>some more structured text</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldClosePartialTags()
        {
            const string input = "<p>a partial tag";
            const string expected = "<p>a partial tag</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldIgnoreUnmatchedCloseTags()
        {
            const string input = "<p>a broken</a> tag</p>";
            const string expected = "<p>a broken tag</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldFixNestedParagraphTags()
        {
            const string input = "<p>a <p>bit of</p> text</p>";
            const string expected = "<p>a </p><p>bit of</p><p> text</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldNestListItemsCorrectly()
        {
            const string input = "<p>a <li>few<li>simple<li>points of text</p>";
            const string expected = "<p>a </p><ul><li>few</li><li>simple</li><li>points of text</li></ul>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldNotCreateBadlyNestedTagsWhenAddingRequiredParents()
        {
            const string input = "<p>a <td>bit of</td> text</p>";
            const string expected = "<p>a </p><table><tr><td>bit of</td></tr></table><p> text</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldCloseNestedPartialTags()
        {
            const string input = "<p>a <strong>partial tag</p>";
            const string expected = "<p>a <strong>partial tag</strong></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldStripExtraCloseTags()
        {
            const string input = "<p>some text</p></p>";
            const string expected = "<p>some text</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldStripDisallowedAttrbiutes()
        {
            const string input = "<p onclick=\"danger();\">yo</p>";
            const string expected = "<p>yo</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldStripEmptyTags()
        {
            const string input = "<p>some text</p><p></p>";
            const string expected = "<p>some text</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldPreserveEmptyTagsForThoseTagsThatRequireIt()
        {
            const string input = "<iframe></iframe><table><tr><td></td></tr></table>";
            const string expected = "<iframe></iframe><table><tr><td></td></tr></table>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
        }

        [Test]
        public void ShouldStripNestedEmptyTags()
        {
            const string input = "<p>some text</p><ul><li> &#160; </li></ul>";
            const string expected = "<p>some text</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldStripTagsWithOnlyWhitespaceInThem()
        {
            const string input = "<p>  </p>";
            var expected = string.Empty;
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldStripTagsWithOnlyEncodedWhitespaceInThem()
        {
            const string input = "<p>&nbsp;&#160;</p>";
            var expected = string.Empty;
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldStripTagsWithOnlyMixedWhitespaceInThem()
        {
            const string input = "<p> &nbsp;&#160; &#160;</p>";
            var expected = string.Empty;
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldStripDisallowedTags()
        {
            const string input = "<form><p>yo</p></form>";
            const string expected = "<p>yo</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldUpscaleBoldTagsToStrongTags()
        {
            const string input = "<p>some <b>bold</b> text</p>";
            const string expected = "<p>some <strong>bold</strong> text</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldUpscaleItalicTagsToEmphasisTags()
        {
            const string input = "<p>some <i>italic</i> text</p>";
            const string expected = "<p>some <em>italic</em> text</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldReduceShortcuttingTags()
        {
            const string input = "<p><img></img></p>";
            const string expected = "<p><img /></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldPreserveKnownAttributes()
        {
            const string input = "<p><a href=\"abc.htm\">text</a></p>";
            const string expected = "<p><a href=\"abc.htm\">text</a></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldPreserveKnownAttributesInShortcuttedTags()
        {
            const string input = "<p><img src=\"pic.jpg\" /></p>";
            const string expected = "<p><img src=\"pic.jpg\" /></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldPreserveKnownAttributesWhenReducingShortcuttedTags()
        {
            const string input = "<p><img src=\"pic.jpg\"></img></p>";
            const string expected = "<p><img src=\"pic.jpg\" /></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldAddRequiredParents()
        {
            const string input = "head<td>a cell</td>tail";
            const string expected = "<p>head</p><table><tr><td>a cell</td></tr></table><p>tail</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldAddRequiredParentsSparingly()
        {
            const string input = "head<td>a cell</td><td>another cell</td>tail";
            const string expected = "<p>head</p><table><tr><td>a cell</td><td>another cell</td></tr></table><p>tail</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldCollapseAnInjectionWhenANonWhiteSpaceBlobIsEncountered()
        {
            const string input = "head<td>a cell</td> a <td>another cell</td>tail";
            const string expected = "<p>head</p><table><tr><td>a cell</td></tr></table><p> a </p><table><tr><td>another cell</td></tr></table><p>tail</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldNotCollapseAnInjectionWhenAWhiteSpaceBlobIsEncountered()
        {
            const string input = "head<td>a cell</td>  <td>another cell</td>tail";
            const string expected = "<p>head</p><table><tr><td>a cell</td>  <td>another cell</td></tr></table><p>tail</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldStripComments()
        {
            const string input = "head<!-- comment -->tail";
            const string expected = "<p>headtail</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldEncodeSpecialCharacters()
        {
            const string input = "dogs & cats";
            const string expected = "<p>dogs &#38; cats</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldEncodeSpecialCharactersInAttributes()
        {
            const string input = "<p><a href=\"dogs & cats\">text</a></p>";
            const string expected = "<p><a href=\"dogs&#32;&#38;&#32;cats\">text</a></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldNotDoubleEncodeCorrectlyEncodedCharacters()
        {
            const string input = "dogs &amp;&nbsp; cats & amp; &#160;";
            const string expected = "<p>dogs &#38;&#160; cats &#38; amp&#59; &#160;</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldNotDoubleEncodeCorrectlyEncodedCharactersInAttributes()
        {
            const string input = "<p><a href=\"dogs &amp;&nbsp; cats & amp; &#160;\">text</a></p>";
            const string expected = "<p><a href=\"dogs&#32;&#38;&#160;&#32;cats&#32;&#38;&#32;amp&#59;&#32;&#160;\">text</a></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldTriggerTransitionalDoctypeForTransitionalTags()
        {
            const string input = "<iframe></iframe>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.IsTrue(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldPreserveButCleanGoogleMapsAndTriggerTransitionalDoctype()
        {
            const string input = "<iframe width=\"425\" height=\"350\" frameborder=\"0\" scrolling=\"no\" marginheight=\"0\" marginwidth=\"0\" src=\"http://maps.google.com/maps/ms?msa=0&amp;msid=100000666902257773673.00045fd51cf352b39888b&amp;hl=en&amp;ie=UTF8&amp;ll=38.907798,-77.043471&amp;spn=0.098949,0.145912&amp;output=embed&amp;s=AARTsJrvOhmM6bttKF0zhdB6gHZJJqE-QQ\"></iframe><br /><small><a href=\"http://maps.google.com/maps/ms?msa=0&amp;msid=100000666902257773673.00045fd51cf352b39888b&amp;hl=en&amp;ie=UTF8&amp;ll=38.907798,-77.043471&amp;spn=0.098949,0.145912&amp;source=embed\" style=\"color:#0000FF;text-align:left\">View Larger Map</a></small>";
            const string expected = "<iframe src=\"http&#58;&#47;&#47;maps.google.com&#47;maps&#47;ms&#63;msa&#61;0&#38;msid&#61;100000666902257773673.00045fd51cf352b39888b&#38;hl&#61;en&#38;ie&#61;UTF8&#38;ll&#61;38.907798,-77.043471&#38;spn&#61;0.098949,0.145912&#38;output&#61;embed&#38;s&#61;AARTsJrvOhmM6bttKF0zhdB6gHZJJqE-QQ\"></iframe><p><a href=\"http&#58;&#47;&#47;maps.google.com&#47;maps&#47;ms&#63;msa&#61;0&#38;msid&#61;100000666902257773673.00045fd51cf352b39888b&#38;hl&#61;en&#38;ie&#61;UTF8&#38;ll&#61;38.907798,-77.043471&#38;spn&#61;0.098949,0.145912&#38;source&#61;embed\">View Larger Map</a></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsTrue(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldNotAllowGoogleMapsToBeNested()
        {
            const string input = "<table><tr><td>Map <iframe width=\"425\" height=\"350\" frameborder=\"0\" scrolling=\"no\" marginheight=\"0\" marginwidth=\"0\" src=\"http://maps.google.com/maps/ms?msa=0&amp;msid=100000666902257773673.00045fd51cf352b39888b&amp;hl=en&amp;ie=UTF8&amp;ll=38.907798,-77.043471&amp;spn=0.098949,0.145912&amp;output=embed&amp;s=AARTsJrvOhmM6bttKF0zhdB6gHZJJqE-QQ\"></iframe><br /><small><a href=\"http://maps.google.com/maps/ms?msa=0&amp;msid=100000666902257773673.00045fd51cf352b39888b&amp;hl=en&amp;ie=UTF8&amp;ll=38.907798,-77.043471&amp;spn=0.098949,0.145912&amp;source=embed\" style=\"color:#0000FF;text-align:left\">View Larger Map</a></small></td></tr></table>";
            const string expected = "<table><tr><td>Map </td></tr></table><iframe src=\"http&#58;&#47;&#47;maps.google.com&#47;maps&#47;ms&#63;msa&#61;0&#38;msid&#61;100000666902257773673.00045fd51cf352b39888b&#38;hl&#61;en&#38;ie&#61;UTF8&#38;ll&#61;38.907798,-77.043471&#38;spn&#61;0.098949,0.145912&#38;output&#61;embed&#38;s&#61;AARTsJrvOhmM6bttKF0zhdB6gHZJJqE-QQ\"></iframe><p><a href=\"http&#58;&#47;&#47;maps.google.com&#47;maps&#47;ms&#63;msa&#61;0&#38;msid&#61;100000666902257773673.00045fd51cf352b39888b&#38;hl&#61;en&#38;ie&#61;UTF8&#38;ll&#61;38.907798,-77.043471&#38;spn&#61;0.098949,0.145912&#38;source&#61;embed\">View Larger Map</a></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
        }

        [Test]
        public void ShouldStripOfficeSmartTags()
        {
            const string input = "<p>This <?xml:namespace prefix = st1 ns = \"urn:schemas-microsoft-com:office:smarttags\" /><st1:place w:st=\"on\"><st1:City w:st=\"on\">Sale</st1:City></st1:place> ends soon<?xml:namespace prefix = o ns = \"urn:schemas-microsoft-com:office:office\" /><o:p></o:p></p>";
            const string expected = "<p>This Sale ends soon</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
        }

        [Test]
        public void ShouldStripNewLineCharacters()
        {
            const string input = "<ul>\r\n<li>Test</li></ul>";
            const string expected = "<ul><li>Test</li></ul>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
        }

        [Test]
        public void ShouldRemoveAllTagsAndReplaceWithSpaces()
        {
            const string input = "<iframe>SomeText</iframe><table><tr>more text<td></td></tr>Value</table>";
            const string expected = "SomeText more text Value";
            var actual = Sanitizer.RemoveAllTags(input);
            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void ShouldNotAllowListWithinParagraph()
        {
            const string input = "<p><ul><li>Hi</li></ul></p>";
            const string expected = "<ul><li>Hi</li></ul>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldPreserveValidParagraphInListItem()
        {
            const string input = "<ol><li><p>Item1</p></li><li>Item2</li></ol>";
            const string expected = "<ol><li><p>Item1</p></li><li>Item2</li></ol>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void ShouldRemoveTheEnclosingDiv()
        {
            const string input = "<div><p><strong>Tester</strong> and something</p></div>";
            const string expected = "<p><strong>Tester</strong> and something</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void KnownBug_ShouldStripDangerousAttributeValues()
        {
            const string input = "<p><a href=\"javascript:danger();\" title=\"Click me\">text</a></p>";
            const string expected = "<p><a title=\"Click&#32;me\">text</a></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void KnownBug_ShouldInjectRequiredAttributes()
        {
            const string input = "<p><img src=\"img.jpg\" /></p>";
            const string expected = "<p><img src=\"img.jpg\" alt=\"\" /></p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }

        [Test]
        public void KnownBug_StripTagsWithoutMinimumRequiredAttributes()
        {
            const string input = "<p><a>Hello</a></p>";
            const string expected = "<p>Hello</p>";
            var actual = Sanitizer.SanitizeMarkup(input);
            Assert.AreEqual(expected, actual.MarkupText);
            Assert.IsFalse(actual.TransitionalDoctypeRequired);
        }
    }
}